package models

import (
	"errors"
	"fmt"

	"strings"

	"io/ioutil"

	"coinsend/btc"
	"coinsend/eth"
	"coinsend/ltc"
	"coinsend/usdt"
	"coinsend/utils"
	"net/http"
	"time"

	"github.com/astaxie/beego/orm"
	"github.com/robfig/cron"
	"github.com/tidwall/gjson"
)

type Worktable struct {
	Id      int
	Billid  int
	Symbol  string
	Uid     int
	Fromadd string
	Toadd   string
	Amount  float64
	Unsigne string
	Signed  string
	Hash    string
	Status  int
	Errors  string
	Created int
}

type Worktable0 struct {
	Id      int
	Billid  int
	Symbol  string
	Uid     int
	From    string
	To      string
	Amount  float64
	Unsigne string
	Signed  string
	Hash    string
	Status  int
	Errors  string
	Created int
}

func init() {
	orm.RegisterModel(new(Worktable))
	//定时循环,检查订单确认数
	c1 := cron.New()
	spec1 := "0 */2 * * * ?"
	c1.AddFunc(spec1, func() {

		CheckWorkStatus()

	})
	c1.Start()
}

//添加发币事务
func ORMAddWork(Symbol, To string, Billid int, Amount float64) error {

	Type, err1 := ORMGetCoinType(Symbol)
	if err1 != nil {
		return errors.New("添加失败," + Symbol + "币种信息不存在" + err1.Error())
	}

	//检查地址合法性
	var Symbol0 = Symbol
	if Type == 10 {
		Symbol0 = "ETH"
		To = strings.ToLower(To)
	}
	if !utils.CheckAddress(Symbol0, To) {
		return errors.New("添加失败," + Symbol + "目的地址不合法")
	}

	o := orm.NewOrm()

	work := new(Worktable)
	work.Billid = Billid
	work.Symbol = Symbol
	work.Toadd = To
	work.Amount = Amount
	work.Status = 10
	work.Created = int(time.Now().Unix())
	_, err := o.Insert(work)
	if err != nil {
		return errors.New("添加失败,报错" + err.Error())
	}
	return nil
}

func GetListWork(Status, Uid int) ([]Worktable0, error) {
	var worklist []Worktable
	var worklist0 []Worktable0
	o := orm.NewOrm()
	if Status == 10 {
		o.QueryTable("Worktable").Filter("Status", Status).All(&worklist)
		for k, _ := range worklist {
			From, _, err := GetAddressNonceByUidSymbol(Uid, worklist[k].Symbol)
			if err != nil {
				return worklist0, errors.New(worklist[k].Symbol + "发币地址未设置")
			}
			worklist[k].Fromadd = From
		}

	} else if Status == 11 {
		o.QueryTable("Worktable").Filter("Status__gt", Status).OrderBy("-Created").Limit(20).All(&worklist)

	} else {
		o.QueryTable("Worktable").Filter("Status", Status).OrderBy("-Created").Limit(10).All(&worklist)

	}

	for _, v := range worklist {
		work0 := new(Worktable0)
		work0.Amount = v.Amount
		work0.Billid = v.Billid
		work0.Created = v.Created
		work0.Errors = v.Errors
		work0.From = v.Fromadd
		work0.Hash = v.Hash
		work0.Id = v.Id
		work0.Signed = v.Signed
		work0.Status = v.Status
		work0.Symbol = v.Symbol
		work0.To = v.Toadd
		work0.Uid = v.Uid
		work0.Unsigne = v.Unsigne

		worklist0 = append(worklist0, *work0)
	}
	return worklist0, nil
}

//获取待签名1111串
func GetUnsigne(Id, Uid int) (string, error) {
	o := orm.NewOrm()
	work := new(Worktable)
	work.Id = Id
	o.Read(work)
	if work.Status == 20 || work.Status == 40 {
		return "", errors.New("该订单非待签名订单")
	}

	if work.Billid == 0 {
		return "", errors.New("错误,发币事务不存在")
	}

	//获取发币地址
	From, Nonce, err := GetAddressNonceByUidSymbol(Uid, work.Symbol)
	if err != nil {
		return "", err
	}

	//获取矿工费
	Contract, Fee, err := ORMGetCoinFeeContract(work.Symbol)
	if err != nil {
		return "", err
	}

	if work.Symbol == "ETH" {

		unsigne, err := eth.GetEthUnSigneString(uint64(Nonce), From, work.Toadd, work.Amount, Fee)
		if err != nil {
			return "", errors.New("生成待签名串失败,原因" + err.Error())
		}
		return unsigne, nil

	} else if work.Symbol == "BTC" {
		unsigne, err := btc.PayTo(From, work.Toadd, work.Amount, Fee)
		if err != nil {
			return "", errors.New("生成待签名串失败,原因" + err.Error())
		}
		return unsigne, nil
	} else if work.Symbol == "LTC" {
		unsigne, err := ltc.PayTo(From, work.Toadd, work.Amount, Fee)
		if err != nil {
			return "", errors.New("生成待签名串失败,原因" + err.Error())
		}
		return unsigne, nil
	} else if work.Symbol == "USDT" {
		unsigne, err := usdt.GetUsdtUnsign(From, work.Toadd, work.Amount, Fee)
		if err != nil {
			return "", errors.New("生成待签名串失败,原因" + err.Error())
		}
		return unsigne, nil
	} else {

		unsigne, err := eth.GetEthTokenUnSigneString(uint64(Nonce), From, work.Toadd, Contract, work.Symbol, work.Amount, Fee, 60000.0)
		if err != nil {
			return "", errors.New("生成待签名串失败,原因" + err.Error())
		}
		return unsigne, nil
	}
}

//广播事务
func SendSigned(Id, Uid int, Signed string) error {
	o := orm.NewOrm()
	work := new(Worktable)
	work.Id = Id
	o.Read(work)

	//获取发币地址
	From, _, _ := GetAddressNonceByUidSymbol(Uid, work.Symbol)

	if work.Billid == 0 {
		return errors.New("广播失败,订单不存在")
	}
	if work.Status == 20 || work.Status == 40 {
		return errors.New("广播失败,订单状态为非待广播状态")
	}
	if work.Symbol == "BTC" || work.Symbol == "USDT" {
		ok, err11 := btc.CheckBTC(Signed, work.Toadd)
		if err11 != nil {
			work.Fromadd = From
			work.Status = 30
			work.Errors = err11.Error()
			work.Uid = Uid
			o.Update(work)
			return errors.New("广播失败,检查目的地址出错" + err11.Error())
		} else if !ok {
			work.Fromadd = From
			work.Status = 30
			work.Errors = "广播失败,目的地址与订单地址不匹配"
			work.Uid = Uid
			o.Update(work)
			return errors.New("广播失败,目的地址与订单地址不匹配")
		}
		hash, err := btc.Broadcast(Signed)
		if err != nil {
			work.Fromadd = From
			work.Status = 30
			work.Errors = err.Error()
			work.Uid = Uid
			o.Update(work)
			return errors.New("广播失败," + err.Error())
		}
		work.Fromadd = From
		work.Hash = hash
		work.Status = 20
		work.Signed = Signed
		work.Uid = Uid
		o.Update(work)

		return nil
	} else if work.Symbol == "LTC" {

		hash, err := ltc.Broadcast(Signed)
		if err != nil {
			work.Fromadd = From
			work.Status = 30
			work.Errors = err.Error()
			work.Uid = Uid
			o.Update(work)
			return errors.New("广播失败," + err.Error())
		}
		work.Fromadd = From
		work.Hash = hash
		work.Status = 20
		work.Signed = Signed
		work.Uid = Uid
		o.Update(work)

		return nil
	} else {
		fmt.Println(strings.ToLower(Signed))
		fmt.Println(work.Toadd[2:])
		fmt.Println(strings.Contains(strings.ToLower(Signed), strings.ToLower(work.Toadd[2:])))
		if strings.Contains(strings.ToLower(Signed), strings.ToLower(work.Toadd[2:])) == false {
			return errors.New("广播失败,目的地址和订单地址不匹配")
		}

		hash, err := eth.SendEthTransaction(Signed)
		if err != nil {
			work.Fromadd = From
			work.Status = 30
			work.Errors = err.Error()
			work.Uid = Uid
			o.Update(work)
			return errors.New("广播失败," + err.Error())
		}
		work.Fromadd = From
		work.Hash = hash
		work.Status = 20
		work.Signed = Signed
		work.Uid = Uid
		o.Update(work)

		AddOneForAddressNonce(Uid, work.Symbol)
		return nil
	}

}

func CheckWorkStatus() {
	var worklist []Worktable
	var cofirm int
	o := orm.NewOrm()
	o.QueryTable("Worktable").Filter("Status", 20).All(&worklist)
	for _, v := range worklist {
		if v.Symbol == "BTC" {
			resp1, _ := http.Get("https://chain.api.btc.com/v3/tx/" + v.Hash)
			defer resp1.Body.Close()
			input, _ := ioutil.ReadAll(resp1.Body)
			obj := gjson.ParseBytes(input)
			cofirm = int(obj.Get("data").Get("confirmations").Int())
		} else if v.Symbol == "LTC" {
			resp1, _ := http.Get("https://api.blockcypher.com/v1/btc/main/txs/" + v.Hash)
			defer resp1.Body.Close()
			input, _ := ioutil.ReadAll(resp1.Body)
			obj := gjson.ParseBytes(input)
			cofirm = int(obj.Get("confirmations").Int())
		} else if v.Symbol == "USDT" {
			cofirm = usdt.GetUSDTCheckHash(v.Hash)
		} else {

			cofirm = eth.GetETHCheckHash(v.Hash)
		}

		fmt.Println("检查hash" + v.Symbol + v.Hash)

		if cofirm > 0 {
			response := utils.AdminReceived(v.Billid, 1, v.Symbol, "")
			if response.Code == 0 {
				work := new(Worktable)
				work.Id = v.Id
				o.Read(work)
				work.Status = 40
				o.Update(work)
			}
		} else if cofirm < 0 {
			work := new(Worktable)
			work.Id = v.Id
			o.Read(work)
			work.Status = 30
			work.Errors = "交易出错,请查看"
			o.Update(work)
		}

	}

}

//
